package com.yami.shop.security.comment.filter;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.yami.shop.common.util.HttpContextUtils;
import com.yami.shop.common.util.Json;
import com.yami.shop.common.util.RedisUtil;
import com.yami.shop.security.comment.constants.SecurityConstants;
import com.yami.shop.security.comment.exception.BadCredentialsException;
import com.yami.shop.security.comment.exception.ImageCodeNotMatchException;
import com.yami.shop.security.comment.exception.UsernameNotFoundException;
import com.yami.shop.security.comment.token.AuthenticationToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.web.HttpRequestMethodNotSupportedException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;

/**
 * 所有的登录filter都继承这个类，用于注入公共方法
 * @author LGH
 */
public class YamiAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {

    private UserDetailsService userDetailsService;

    private PasswordEncoder passwordEncoder;

    protected YamiAuthenticationProcessingFilter(String defaultFilterProcessesUrl) {
        super(defaultFilterProcessesUrl);
    }

    @Autowired
    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }

    @Autowired
    public void setUserDetailsService(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    @Override
    @Autowired
    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
        super.setAuthenticationManager(authenticationManager);
    }

    @Override
    @Autowired
    public void setAuthenticationSuccessHandler(AuthenticationSuccessHandler successHandler) {
        super.setAuthenticationSuccessHandler(successHandler);
    }

    @Override
    @Autowired
    public void setAuthenticationFailureHandler(AuthenticationFailureHandler failureHandler) {
        super.setAuthenticationFailureHandler(failureHandler);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, ServletException {
        // 获取前端国际化状态并设置

        if (!ServletUtil.METHOD_POST.equals(request.getMethod())) {
            throw new HttpRequestMethodNotSupportedException(request.getMethod(), new String[] { "POST" });
        }

        AuthenticationToken authenticationToken = Json.parseObject(HttpContextUtils.getStringFromStream(request), AuthenticationToken.class);

        UserDetails userDetails = getUserDetails(authenticationToken);

        return handleAuthenticationToken(authenticationToken,userDetails);
    }

    /**
     * 获取用户信息
     * @param authenticationToken
     * @return
     */
    protected UserDetails getUserDetails(AuthenticationToken authenticationToken) {
        checkKaptcha(authenticationToken);
        UserDetails user;
        try {
            user = userDetailsService.loadUserByUsername(authenticationToken.getPrincipal());
        } catch (UsernameNotFoundException var6) {
            // 账号或密码不正确
            throw new UsernameNotFoundException("yami.user.account.error");
        }
        if (!user.isEnabled()) {
            // 账号已被锁定,请联系管理员
            throw new UsernameNotFoundException("yami.user.account.lock");
        }


        String encodedPassword = user.getPassword();
        String rawPassword = authenticationToken.getCredentials().toString();

        // 密码不正确
        if (!passwordEncoder.matches(rawPassword,encodedPassword)){
            // 账号或密码不正确
            throw new BadCredentialsException("yami.user.account.error");
        }
        return user;
    }


    /**
     * 保存用户信息
     */
    protected AuthenticationToken handleAuthenticationToken(AuthenticationToken authentication, UserDetails userDetails) {
        // 保存用户信息
        authentication.setPrincipal(userDetails.getUsername());
        authentication.setDetails(userDetails);
        authentication.setAuthenticated(true);
        return authentication;
    }

    /**
     * 检验验证码
     */
    protected void checkKaptcha(AuthenticationToken authenticationToken) {
        String kaptchaKey = SecurityConstants.SPRING_SECURITY_RESTFUL_IMAGE_CODE + authenticationToken.getSessionUUID();

        String kaptcha = RedisUtil.get(kaptchaKey);

        RedisUtil.del(kaptchaKey);

        if(StrUtil.isBlank(authenticationToken.getImageCode()) || !authenticationToken.getImageCode().equalsIgnoreCase(kaptcha)){
            // 验证码有误或已过期
            throw new ImageCodeNotMatchException("yami.user.code.error");
        }
    }

    /**
     * 检验验证码
     */
    protected void getUserDetailsAndCheckPassword(AuthenticationToken authenticationToken) {
        String kaptchaKey = SecurityConstants.SPRING_SECURITY_RESTFUL_IMAGE_CODE + authenticationToken.getSessionUUID();

        String kaptcha = RedisUtil.get(kaptchaKey);

        RedisUtil.del(kaptchaKey);

        if(StrUtil.isBlank(authenticationToken.getImageCode()) || !authenticationToken.getImageCode().equalsIgnoreCase(kaptcha)){
            // 验证码有误或已过期
            throw new ImageCodeNotMatchException("yami.user.code.error");
        }
    }

}
